package huriezy.quickcontacts.activities.fragments;

import huriezy.quickcontacts.R;
import huriezy.quickcontacts.models.ContactController;
import huriezy.quickcontacts.models.LogDebug;
import huriezy.quickcontacts.models.interfaces.IAddressDetectionListener;
import huriezy.quickcontacts.models.interfaces.IContactManager;
import huriezy.quickcontacts.models.interfaces.ILocationManager;

import java.util.ArrayList;
import java.util.List;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.location.Address;
import android.location.Location;
import android.location.LocationProvider;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class LocationFragment extends ContactFragment implements IAddressDetectionListener {

	public static final int		LIMIT_ADDRESSES_SHOWN	= 5;

	private ILocationManager	contactLocationManager;
	private int					limitClickOnButton		= 0;

	private Address				lastAddress				= null;
	private float				lastAccuracy			= -1;

	private String				locationUpdateText		= null;
	private String				accuracyLabelText		= null;
	private String				noAddressLabel			= null;
	private String				updateDescriptionText	= null;

	public static LocationFragment newInstance(String address) {
		LocationFragment instance = new LocationFragment();
		Bundle args = new Bundle();
		args.putString(IContactManager.ADDRESS_TAG, address);
		instance.setArguments(args);
		return instance;
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		super.onCreateView(inflater, container, savedInstanceState);
		View result = inflater.inflate(R.layout.fragment_location, container, false);
		Bundle args = getArguments();
		if (args == null) {
			args = savedInstanceState;
			LogDebug.info(" * Use savedInstanceState for " + getClass().getSimpleName(), getClass());
		}
		else {
			LogDebug.info(" * Use newInstance bundle for " + getClass().getSimpleName(), getClass());
		}
		if (args != null) {
			String address = args.getString(IContactManager.ADDRESS_TAG);
			setAddress(address, result);
		}
		else {
			LogDebug.debug("No saved informations.", getClass());
		}

		TextView closestLocationView = (TextView) result.findViewById(R.id.closest_location_textView);
		TextView accuracyView = (TextView) result.findViewById(R.id.accuracy_textView);
		if (noAddressLabel == null) {
			noAddressLabel = getResources().getString(R.string.no_address_label_text);
		}
		closestLocationView.setText(noAddressLabel);
		closestLocationView.setGravity(Gravity.CENTER);
		accuracyView.setText("");

		contactLocationManager = ContactController.getInstance().getLocationManager(getActivity());
		contactLocationManager.setAddressDetectionListener(this);
		initActions(result);

		return result;
	}

	@Override
	public void clearContactData() {
		setAddress("", getView());
	}

	@Override
	public void saveContactData() {
		IContactManager contactManager = ContactController.getInstance().getContactManager(getActivity());
		contactManager.putContactData(IContactManager.ADDRESS_TAG, getAddress(getView()));
	}

	@Override
	public void onStop() {
		super.onStop();
		contactLocationManager.stopLocationUpdates();
	}

	private void resetLocationSearch() {
		contactLocationManager.stopLocationUpdates();
		lastAddress = null;
		lastAccuracy = -1;
		limitClickOnButton = 0;
		Button currentLocationButton = (Button) getActivity().findViewById(R.id.use_current_location_button);
		TextView closestLocationView = (TextView) getActivity().findViewById(R.id.closest_location_textView);
		TextView accuracyView = (TextView) getActivity().findViewById(R.id.accuracy_textView);
		if (noAddressLabel == null) {
			noAddressLabel = getResources().getString(R.string.no_address_label_text);
		}
		closestLocationView.setText(noAddressLabel);
		closestLocationView.setGravity(Gravity.CENTER);
		accuracyView.setText("");
		currentLocationButton.setTextColor(Color.BLACK);
	}

	/**
	 * Init this {@link Fragment} actions
	 * 
	 * @param result
	 */
	private void initActions(View result) {
		final Button currentLocationButton = (Button) result.findViewById(R.id.use_current_location_button);
		final Button useThisLocation = (Button) result.findViewById(R.id.use_location_button);

		if (currentLocationButton != null) {
			currentLocationButton.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
					askForCurrentLocation();
				}
			});
		}
		else {
			LogDebug.info("Cannot find button for current location", getClass());
		}

		if (useThisLocation != null) {
			useThisLocation.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
					showClosestLocationFields(false);
					if (lastAddress != null) {
						updateAddress(addressToString(lastAddress));
					}
					else {
						String noAddressMessage = getResources().getString(R.string.no_address_error_message);
						Toast.makeText(getActivity(), noAddressMessage, Toast.LENGTH_SHORT).show();
					}
					resetLocationSearch();
				}
			});
		}
	}

	/**
	 * Search the current location using the list of compatible
	 * {@link LocationProvider}.
	 * 
	 * @return the current {@link Location}
	 */
	private void askForCurrentLocation() {
		LogDebug.info("Asking for current location", getClass());
		if (!contactLocationManager.isProviderAvailable()) {
			showProviderAskingDialog();
		}
		else {
			showClosestLocationFields(true);
			
			final Button currentLocationButton = (Button) getView().findViewById(R.id.use_current_location_button);

			currentLocationButton.setTextColor(Color.RED);

			if (limitClickOnButton == 0) {
				contactLocationManager.startLocationUpdates();
				
				Location lastKnownLocation = contactLocationManager.getLastKnownLocation();
				if (lastKnownLocation != null) {
					Address lastAddress = contactLocationManager.getAddressFromLocation(lastKnownLocation);
					float lastAccuracy = lastKnownLocation.getAccuracy();
					if(lastAddress != null && lastAccuracy > 0){
						onAddressDetected(lastAddress, lastAccuracy);
					}
				}
				
				LogDebug.info("Last known position : " + lastAddress, getClass());
				if (updateDescriptionText == null) {
					updateDescriptionText = getResources().getString(R.string.update_location_description_text);
				}
				Toast.makeText(getActivity(), updateDescriptionText, Toast.LENGTH_LONG);
			}
			if (limitClickOnButton < 3) {
				String waitMessage = getResources().getString(R.string.wait_location_text);
				Toast.makeText(getActivity(), waitMessage, Toast.LENGTH_SHORT).show();
			}
			else if (limitClickOnButton == 3) {
				String waitMessage = getResources().getString(R.string.wait_forced_location_text);
				Toast.makeText(getActivity(), waitMessage, Toast.LENGTH_LONG).show();
			}
			limitClickOnButton++;

		}
	}

	@Override
	public void onAddressDetected(Address address, float accuracy) {
		LogDebug.info("Accuracy : " + accuracy + ", last accuracy : " + lastAccuracy, getClass());
		if (lastAccuracy < 0 || lastAccuracy > accuracy) {
			lastAccuracy = accuracy;
			lastAddress = address;
			refreshWaitingAddressFields();
		}
	}

	/**
	 * Refresh location selection field with last informations
	 */
	private void refreshWaitingAddressFields() {
		TextView closestLocationTextView = (TextView) getActivity().findViewById(R.id.closest_location_textView);
		TextView accuracyTextView = (TextView) getActivity().findViewById(R.id.accuracy_textView);
		if (closestLocationTextView != null) {
			closestLocationTextView.setText(addressToString(lastAddress));
		}
		if (accuracyTextView != null) {
			if (accuracyLabelText == null) {
				accuracyLabelText = getResources().getString(R.string.accuracy_text);
			}
			accuracyTextView.setText(accuracyLabelText + Float.toString(lastAccuracy) + "m");
		}
	}

	/**
	 * Show or hide fields used for location selection.
	 * 
	 * @param show
	 */
	public void showClosestLocationFields(boolean show) {
		View closestLocationLabelView = getActivity().findViewById(R.id.closest_location_label_textView);
		View closestLocationView = getActivity().findViewById(R.id.closest_location_textView);
		View useLocationView = getActivity().findViewById(R.id.use_location_button);
		View accuracyView = getActivity().findViewById(R.id.accuracy_textView);
		if (show) {
			closestLocationLabelView.setVisibility(View.VISIBLE);
			closestLocationView.setVisibility(View.VISIBLE);
			useLocationView.setVisibility(View.VISIBLE);
			accuracyView.setVisibility(View.VISIBLE);
		}
		else {
			closestLocationLabelView.setVisibility(View.GONE);
			closestLocationView.setVisibility(View.GONE);
			useLocationView.setVisibility(View.GONE);
			accuracyView.setVisibility(View.GONE);
		}
	}

	/**
	 * 
	 */
	private void updateAddress(String address) {
		setAddress(address, getView());
		if (locationUpdateText == null) {
			locationUpdateText = getActivity().getResources().getString(R.string.location_updated_text);
		}
		Toast.makeText(getActivity(), locationUpdateText, Toast.LENGTH_SHORT).show();
	}

	/**
	 * Show a dialog that ask the user to turn on the provider we need to
	 * proceed to the location updates.
	 */
	private void showProviderAskingDialog() {
		final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
		builder.setMessage("Your GPS seems to be disabled, do you want to enable it?").setCancelable(false)
				.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
					public void onClick(final DialogInterface dialog, final int id) {
						startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
					}
				}).setNegativeButton("No", new DialogInterface.OnClickListener() {
					public void onClick(final DialogInterface dialog, final int id) {
						dialog.cancel();
					}
				});
		final AlertDialog alert = builder.create();
		alert.show();
	}

	/**
	 * Translate address into a readable String.
	 * 
	 * @param address
	 *            the concerned Address
	 * @return the readable {@link String}
	 */
	public String addressToString(Address address) {
		StringBuilder result = new StringBuilder();
		boolean first = true;
		if (address != null) {
			for (int index = 0; index < address.getMaxAddressLineIndex(); ++index) {
				if (!first) {
					result.append(",");
				}
				result.append(address.getAddressLine(index));
				first = false;
			}
		}
		return result.toString();
	}

	/**
	 * Translate list of addresses into a list of readable String.
	 * 
	 * @param address
	 *            the concerned Address
	 * @return the readable {@link String}
	 */
	public List<String> addressToString(List<Address> listAddresses) {
		final List<String> result = new ArrayList<String>();
		for (Address address : listAddresses) {
			String strAddress = addressToString(address);
			LogDebug.info("Address is " + strAddress, getClass());
			result.add(strAddress);
		}
		return result;
	}

	public boolean isSameAddress(Address first, Address second) {
		boolean result = false;
		if (first == second) {
			result = true;
		}
		else if (first != null && second != null) {
			result = first.equals(second);
			if (!result) {
				// Test if equals method not implemented
				String firstAddressStr = addressToString(first);
				String secondAddressStr = addressToString(second);
				result = firstAddressStr.equalsIgnoreCase(secondAddressStr);
			}
		}
		return result;
	}

	public void setAddress(String address, View view) {
		EditText edittext = getAddressEditText(view);
		if (edittext != null) {
			edittext.setText(address);
		}
	}

	public String getAddress(View view) {
		String result = "";
		EditText edittext = getAddressEditText(view);
		if (edittext != null) {
			result = edittext.getText().toString();
		}
		return result;
	}

	private EditText getAddressEditText(View view) {
		if (view != null) {
			return (EditText) view.findViewById(R.id.contact_address_editText);
		}
		else {
			LogDebug.warn("No Edit text view founded for contact address.", getClass());
		}
		return null;
	}
}
